package com.flute.icrawler.framework.framework;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;

import com.flute.icrawler.framework.framework.listener.ICrawlTaskListener;

/**
 * url容器的一个ConcurrentLinkedQueue的实现
 * 线程安全，对url采用先进先出的方式
 * @author Administrator
 *
 */
/**
 * @author Administrator
 * 
 * 
 * 
 */
public class CrawlUrlPool implements ICrawlUrlPool {

	/**
	 * 
	 */
	private static final long serialVersionUID = -7047483878425719237L;
	/**
	 * 在等待中的url
	 */
	protected ConcurrentLinkedQueue<String> waitQueue;
	/**
	 * 已经处理成功的url
	 */
	protected ConcurrentLinkedQueue<String> sucessedQueue;

	protected ConcurrentLinkedQueue<String> proccessingQueue;

	/**
	 * 已经处理失败的url
	 */
	protected ConcurrentLinkedQueue<String> failedQueue;
	/**
	 * 需要重新放入处理链条的url
	 */
	protected ConcurrentLinkedQueue<String> retriedQueue;
	/**
	 * 所有以上url
	 */
	protected ConcurrentLinkedQueue<String> allQueue;

	protected HashMap<String, Integer> deepMaps;

	protected CrawlJob job;

	public CrawlUrlPool() {
		this.waitQueue = new ConcurrentLinkedQueue<String>();// monitor
		this.sucessedQueue = new ConcurrentLinkedQueue<String>();// monitor
		this.retriedQueue = new ConcurrentLinkedQueue<String>();// monitor
		this.failedQueue = new ConcurrentLinkedQueue<String>();// monitor
		this.allQueue = new ConcurrentLinkedQueue<String>();
		this.proccessingQueue = new ConcurrentLinkedQueue<String>();

		this.deepMaps = new HashMap<String, Integer>();

		if (job != null)
			initialize();

		try {
			UnicastRemoteObject.exportObject(this);
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}

	private void initialize() {
		for (Seed seed : job.getSettings().getSeeds()) {
			waitQueue.add(seed.getUrl());
			deepMaps.put(seed.getUrl(), 1);
		}
	}

	/*
	 * @see com.cpkf.yyjd.crawler.framework.ICrawlUrlPool#nextUrl()
	 */
	public synchronized CrawlUrl nextUrl() {
		CrawlUrl url = null;
		if (waitQueue.size() > 0) {
			String nextUrl = waitQueue.poll();
			url = new CrawlUrl(job, nextUrl);
			this.proccessingQueue.add(nextUrl);
		} else if (retriedQueue.size() > 0) {
			String nextUrl = retriedQueue.poll();
			url = new CrawlUrl(job, nextUrl);
			this.proccessingQueue.add(nextUrl);
		}

		return url;
	}

	/*
	 * @see com.cpkf.yyjd.crawler.framework.ICrawlUrlPool#hasNext()
	 */
	public synchronized boolean hasNext() {
		return waitQueue.size() > 0 || retriedQueue.size() > 0;
	}

	public synchronized boolean isProcessing() {
		return proccessingQueue.size() > 0;
	}

	/*
	 * @see
	 * com.cpkf.yyjd.crawler.framework.ICrawlUrlPool#fail(com.cpkf.yyjd.crawler
	 * .framework.CrawlUrl)
	 */
	public synchronized void fail(CrawlUrl url) {
		this.failedQueue.add(url.getUrl());
		this.proccessingQueue.remove(url.getUrl());
		this.allQueue.add(url.getUrl());
	}

	@Override
	public synchronized void filter(CrawlUrl url) throws RemoteException {
		// TODO Auto-generated method stub
		this.proccessingQueue.remove(url.getUrl());
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.cpkf.yyjd.crawler.framework.ICrawlUrlPool#success(com.cpkf.yyjd.crawler
	 * .framework.CrawlUrl)
	 */
	public synchronized void success(CrawlUrl url) {
		this.sucessedQueue.add(url.getUrl());
		this.proccessingQueue.remove(url.getUrl());
		this.allQueue.add(url.getUrl());
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.cpkf.yyjd.crawler.framework.ICrawlUrlPool#retry(com.cpkf.yyjd.crawler
	 * .framework.CrawlUrl)
	 */
	public synchronized void retry(CrawlUrl url) {
		this.retriedQueue.add(url.getUrl());
		this.proccessingQueue.remove(url.getUrl());
		this.allQueue.add(url.getUrl());
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.cpkf.yyjd.crawler.framework.ICrawlUrlPool#add(java.lang.String)
	 */
	public synchronized void add(CrawlUrl currentUrl, String url) {
		this.waitQueue.add(url);
		this.allQueue.add(url);
		int newDeep = deepMaps.get(currentUrl.getUrl()) + 1;
		if (!deepMaps.containsKey(url)) {
			this.deepMaps.put(url, newDeep);
		} else {
			int recordedDeep = deepMaps.get(url);
			if (recordedDeep > newDeep) {
				deepMaps.put(url, newDeep);
			}
		}
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see com.flute.icrawler.framework.framework.ICrawlUrlPool#contains(java.lang.String)
	 */
	public boolean contains(String url) {
		synchronized (allQueue) {
			return allQueue.contains(url);
		}
	}

	@Override
	public CrawlJob getCrawlJob() {
		return job;
	}

	public void setJob(CrawlJob job) {
		this.job = job;
		if (job != null)
			initialize();
	}

	public void addUpdateUrl(CrawlUrl url) throws RemoteException {
		this.waitQueue.add(url.getUrl());
		this.allQueue.add(url.getUrl());
		int newDeep = deepMaps.get(url.getUrl());

		if (!deepMaps.containsKey(url.getUrl())) {
			newDeep = 1;
		}

		if (!deepMaps.containsKey(url.getUrl())) {
			this.deepMaps.put(url.getUrl(), newDeep);
		} else {
			int recordedDeep = deepMaps.get(url.getUrl());
			if (recordedDeep > newDeep) {
				deepMaps.put(url.getUrl(), newDeep);
			}
		}
	}



	@Override
	public void add(CrawlUrl url) throws RemoteException {
		// TODO Auto-generated method stub

	}

	@Override
	public List<CrawlUrl> nextUrl(int n) throws RemoteException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void addAll(List<CrawlUrl> crawlUrls) throws RemoteException {
		// TODO Auto-generated method stub

	}

	@Override
	public void notityCrawlUrl(CrawlUrl url) throws RemoteException {
		// TODO Auto-generated method stub
		
	}

}